efl/src/lib/eina/eina_share_common.c

950 lines
26 KiB
C
Raw Normal View History

/* EINA - EFL data type library
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010
* Carsten Haitzler,
* Jorge Luis Zapata Muga,
* Cedric Bail,
* Gustavo Sverzut Barbieri
* Tom Hacohen
* Brett Nash
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (C) 2008 Peter Wehrfritz
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of the Software and its Copyright notices. In addition publicly
* documented acknowledgment must be given that this software has been used if no
* source code of this software is made available publicly. This includes
* acknowledgments in either Copyright notices, Manuals, Publicity and Marketing
* documents or any documentation provided with any product containing this
* software. This License does not apply to any software that links to the
* libraries provided by this software (statically or dynamically), but only to
* the software provided.
*
* Please see the OLD-COPYING.PLAIN for a plain-english explanation of this notice
* and it's intent.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#ifdef EFL_HAVE_POSIX_THREADS
# include <pthread.h>
#endif
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "eina_config.h"
#include "eina_private.h"
#include "eina_hash.h"
#include "eina_rbtree.h"
#include "eina_error.h"
#include "eina_lock.h"
/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
#include "eina_safety_checks.h"
#include "eina_share_common.h"
/*============================================================================*
2010-07-27 19:37:05 -07:00
* Local *
*============================================================================*/
/**
* @cond LOCAL
*/
#define EINA_SHARE_COMMON_BUCKETS 256
#define EINA_SHARE_COMMON_MASK 0xFF
static const char EINA_MAGIC_SHARE_STR[] = "Eina Share";
static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head";
static int _eina_share_common_count = 0;
2010-07-27 19:37:05 -07:00
#define EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(d, unlock, ...) \
do { \
if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_SHARE_HEAD)) \
{ \
EINA_MAGIC_FAIL((d), EINA_MAGIC_SHARE_HEAD); \
unlock; \
return __VA_ARGS__; \
} \
} while (0)
#define EINA_MAGIC_CHECK_SHARE_COMMON_NODE(d, _node_magic, unlock) \
do { \
if (!EINA_MAGIC_CHECK((d), _node_magic)) \
{ \
EINA_MAGIC_FAIL((d), _node_magic); \
unlock; \
2010-07-27 19:37:05 -07:00
} \
} while (0)
#ifdef EINA_SHARE_USAGE
2010-07-27 19:37:05 -07:00
typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population;
#endif
2010-07-27 19:37:05 -07:00
typedef struct _Eina_Share_Common Eina_Share_Common;
typedef struct _Eina_Share_Common_Node Eina_Share_Common_Node;
typedef struct _Eina_Share_Common_Head Eina_Share_Common_Head;
2010-07-27 19:37:05 -07:00
struct _Eina_Share
{
Eina_Share_Common *share;
Eina_Magic node_magic;
#ifdef EINA_SHARE_COMMON_USAGE
Eina_Share_Common_Population population;
int max_node_population;
#endif
};
struct _Eina_Share_Common
{
Eina_Share_Common_Head *buckets[EINA_SHARE_COMMON_BUCKETS];
EINA_MAGIC
};
struct _Eina_Share_Common_Node
{
Eina_Share_Common_Node *next;
EINA_MAGIC
2010-07-27 19:37:05 -07:00
unsigned int length;
unsigned int references;
char str[];
};
struct _Eina_Share_Common_Head
{
EINA_RBTREE;
EINA_MAGIC
2010-07-27 19:37:05 -07:00
int hash;
#ifdef EINA_SHARE_COMMON_USAGE
2010-07-27 19:37:05 -07:00
int population;
#endif
Eina_Share_Common_Node *head;
2010-07-27 19:37:05 -07:00
Eina_Share_Common_Node builtin_node;
};
Eina_Bool _share_common_threads_activated = EINA_FALSE;
static Eina_Lock _mutex_big;
#ifdef EINA_SHARE_COMMON_USAGE
struct _Eina_Share_Common_Population
{
int count;
int max;
};
static Eina_Share_Common_Population population = { 0, 0 };
static Eina_Share_Common_Population population_group[4] =
2010-07-27 19:37:05 -07:00
{
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
};
static void
_eina_share_common_population_init(Eina_Share *share)
{
unsigned int i;
2010-07-27 19:37:05 -07:00
for (i = 0;
i < sizeof (share->population_group) /
sizeof (share->population_group[0]);
++i)
{
share->population_group[i].count = 0;
share->population_group[i].max = 0;
}
}
static void
_eina_share_common_population_shutdown(Eina_Share *share)
{
unsigned int i;
share->max_node_population = 0;
share->population.count = 0;
share->population.max = 0;
2010-07-27 19:37:05 -07:00
for (i = 0;
i < sizeof (share->population_group) /
sizeof (share->population_group[0]);
++i)
{
share->population_group[i].count = 0;
share->population_group[i].max = 0;
}
}
static void
_eina_share_common_population_stats(Eina_Share *share)
{
unsigned int i;
2010-07-27 19:37:05 -07:00
fprintf(stderr, "eina share_common statistic:\n");
fprintf(stderr,
" * maximum shared strings : %i\n",
share->population.max);
2010-07-27 19:37:05 -07:00
fprintf(stderr,
" * maximum shared strings per node : %i\n",
share->max_node_population);
2010-07-27 19:37:05 -07:00
for (i = 0;
i < sizeof (share->population_group) /
sizeof (share->population_group[0]);
++i)
fprintf(stderr,
"DDD: %i strings of length %u, max strings: %i\n",
2010-07-27 19:37:05 -07:00
share->population_group[i].count,
i,
share->population_group[i].max);
}
void
eina_share_common_population_add(Eina_Share *share, int slen)
{
eina_lock_take(&_mutex_big);
share->population.count++;
if (share->population.count > share->population.max)
2010-07-27 19:37:05 -07:00
share->population.max = share->population.count;
if (slen < 4)
{
2010-07-27 19:37:05 -07:00
share->population_group[slen].count++;
if (share->population_group[slen].count >
share->population_group[slen].max)
share->population_group[slen].max =
share->population_group[slen].count;
}
eina_lock_release(&_mutex_big);
}
void
eina_share_common_population_del(Eina_Share *share, int slen)
{
eina_lock_take(&_mutex_big);
share->population.count--;
if (slen < 4)
2010-07-27 19:37:05 -07:00
share->population_group[slen].count--;
eina_lock_release(&_mutex_big);
}
static void
2010-07-27 19:37:05 -07:00
_eina_share_common_population_head_init(Eina_Share *share,
Eina_Share_Common_Head *head)
{
head->population = 1;
}
static void
2010-07-27 19:37:05 -07:00
_eina_share_common_population_head_add(Eina_Share *share,
Eina_Share_Common_Head *head)
{
head->population++;
if (head->population > share->max_node_population)
2010-07-27 19:37:05 -07:00
share->max_node_population = head->population;
}
static void
2010-07-27 19:37:05 -07:00
_eina_share_common_population_head_del(Eina_Share *share,
Eina_Share_Common_Head *head)
{
head->population--;
}
#else /* EINA_SHARE_COMMON_USAGE undefined */
2010-07-27 19:37:05 -07:00
static void _eina_share_common_population_init(__UNUSED__ Eina_Share *share) {
}
static void _eina_share_common_population_shutdown(__UNUSED__ Eina_Share *share)
{
}
static void _eina_share_common_population_stats(__UNUSED__ Eina_Share *share) {
}
void eina_share_common_population_add(__UNUSED__ Eina_Share *share,
__UNUSED__ int slen) {
}
void eina_share_common_population_del(__UNUSED__ Eina_Share *share,
__UNUSED__ int slen) {
}
static void _eina_share_common_population_head_init(
__UNUSED__ Eina_Share *share,
__UNUSED__ Eina_Share_Common_Head *head) {
}
static void _eina_share_common_population_head_add(
__UNUSED__ Eina_Share *share,
__UNUSED__
Eina_Share_Common_Head *head) {
}
static void _eina_share_common_population_head_del(
__UNUSED__ Eina_Share *share,
__UNUSED__
Eina_Share_Common_Head *head) {
}
#endif
static int
2010-07-27 19:37:05 -07:00
_eina_share_common_cmp(const Eina_Share_Common_Head *ed,
const int *hash,
__UNUSED__ int length,
__UNUSED__ void *data)
{
EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, , 0);
return ed->hash - *hash;
}
static Eina_Rbtree_Direction
2010-07-27 19:37:05 -07:00
_eina_share_common_node(const Eina_Share_Common_Head *left,
const Eina_Share_Common_Head *right,
__UNUSED__ void *data)
{
2010-07-27 19:37:05 -07:00
EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(left, , 0);
EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(right, , 0);
if (left->hash - right->hash < 0)
2010-07-27 19:37:05 -07:00
return EINA_RBTREE_LEFT;
return EINA_RBTREE_RIGHT;
}
static void
_eina_share_common_head_free(Eina_Share_Common_Head *ed, __UNUSED__ void *data)
{
EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, );
while (ed->head)
{
2010-07-27 19:37:05 -07:00
Eina_Share_Common_Node *el = ed->head;
2010-07-27 19:37:05 -07:00
ed->head = ed->head->next;
if (el != &ed->builtin_node)
MAGIC_FREE(el);
}
2010-07-27 19:37:05 -07:00
MAGIC_FREE(ed);
}
static void
2010-07-27 19:37:05 -07:00
_eina_share_common_node_init(Eina_Share_Common_Node *node,
const char *str,
int slen,
unsigned int null_size,
Eina_Magic node_magic)
{
EINA_MAGIC_SET(node, node_magic);
node->references = 1;
node->length = slen;
memcpy(node->str, str, slen);
memset(node->str + slen, 0, null_size); /* Nullify the null */
(void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
}
static Eina_Share_Common_Head *
_eina_share_common_head_alloc(int slen)
{
Eina_Share_Common_Head *head;
const size_t head_size = offsetof(Eina_Share_Common_Head, builtin_node.str);
head = malloc(head_size + slen);
if (!head)
2010-07-27 19:37:05 -07:00
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return head;
}
static const char *
2010-07-27 19:37:05 -07:00
_eina_share_common_add_head(Eina_Share *share,
Eina_Share_Common_Head **p_bucket,
int hash,
const char *str,
unsigned int slen,
unsigned int null_size)
{
Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
Eina_Share_Common_Head *head;
head = _eina_share_common_head_alloc(slen + null_size);
if (!head)
2010-07-27 19:37:05 -07:00
return NULL;
EINA_MAGIC_SET(head, EINA_MAGIC_SHARE_HEAD);
head->hash = hash;
head->head = &head->builtin_node;
2010-07-27 19:37:05 -07:00
_eina_share_common_node_init(head->head,
str,
slen,
null_size,
share->node_magic);
head->head->next = NULL;
_eina_share_common_population_head_init(share, head);
*p_tree = eina_rbtree_inline_insert
2010-07-27 19:37:05 -07:00
(*p_tree, EINA_RBTREE_GET(head),
EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
return head->head->str;
}
static void
2010-07-27 19:37:05 -07:00
_eina_share_common_del_head(Eina_Share_Common_Head **p_bucket,
Eina_Share_Common_Head *head)
{
Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
*p_tree = eina_rbtree_inline_remove
2010-07-27 19:37:05 -07:00
(*p_tree, EINA_RBTREE_GET(head),
EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
2010-07-27 19:37:05 -07:00
MAGIC_FREE(head);
}
static inline Eina_Bool
2010-07-27 19:37:05 -07:00
_eina_share_common_node_eq(const Eina_Share_Common_Node *node,
const char *str,
unsigned int slen)
{
return ((node->length == slen) &&
2010-07-27 19:37:05 -07:00
(memcmp(node->str, str, slen) == 0));
}
static Eina_Share_Common_Node *
2010-07-27 19:37:05 -07:00
_eina_share_common_head_find(Eina_Share_Common_Head *head,
const char *str,
unsigned int slen)
{
Eina_Share_Common_Node *node, *prev;
node = head->head;
if (_eina_share_common_node_eq(node, str, slen))
2010-07-27 19:37:05 -07:00
return node;
prev = node;
node = node->next;
for (; node; prev = node, node = node->next)
2010-07-27 19:37:05 -07:00
if (_eina_share_common_node_eq(node, str, slen))
{
/* promote node, make hot items be at the beginning */
prev->next = node->next;
node->next = head->head;
head->head = node;
return node;
}
return NULL;
}
static Eina_Bool
2010-07-27 19:37:05 -07:00
_eina_share_common_head_remove_node(Eina_Share_Common_Head *head,
const Eina_Share_Common_Node *node)
{
Eina_Share_Common_Node *cur, *prev;
if (head->head == node)
{
2010-07-27 19:37:05 -07:00
head->head = node->next;
return 1;
}
prev = head->head;
cur = head->head->next;
for (; cur; prev = cur, cur = cur->next)
2010-07-27 19:37:05 -07:00
if (cur == node)
{
prev->next = cur->next;
return 1;
}
return 0;
}
static Eina_Share_Common_Head *
_eina_share_common_find_hash(Eina_Share_Common_Head *bucket, int hash)
{
2010-07-27 19:37:05 -07:00
return (Eina_Share_Common_Head *)eina_rbtree_inline_lookup
(EINA_RBTREE_GET(bucket), &hash, 0,
EINA_RBTREE_CMP_KEY_CB(_eina_share_common_cmp), NULL);
}
static Eina_Share_Common_Node *
_eina_share_common_node_alloc(unsigned int slen, unsigned int null_size)
{
Eina_Share_Common_Node *node;
const size_t node_size = offsetof(Eina_Share_Common_Node, str);
node = malloc(node_size + slen + null_size);
if (!node)
2010-07-27 19:37:05 -07:00
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
return node;
}
static Eina_Share_Common_Node *
_eina_share_common_node_from_str(const char *str, Eina_Magic node_magic)
{
Eina_Share_Common_Node *node;
const size_t offset = offsetof(Eina_Share_Common_Node, str);
node = (Eina_Share_Common_Node *)(str - offset);
SVN revision: 3 Subject: [E-devel] [PATCH] eina share common check for node type Hello, recentely I've been experiencing a lot of segfaults when running an Elementary application which uses a genlist with some swallowed parts in which I put some elm icons (png files). When running it I often get crashes... Debugging it I found this: ========= CRI<14207>: eina_share_common.c:561 _eina_share_common_node_from_str() *** Eina Magic Check Failed !!! Input handle is wrong type Expected: 98761254 - Eina Stringshare Node Supplied: 6e657070 - (unknown) *** NAUGHTY PROGRAMMER!!! *** SPANK SPANK SPANK!!! *** Now go fix your code. Tut tut tut! //DEBUG: Node referencies 622869060 (slen: 1145307236) Program received signal SIGSEGV, Segmentation fault. eina_share_common_del (share=0x65c810, str=0x7ffff1219150 "5hhu %5hu '% s'\n") at eina_share_common.c:858 858 node->references--; ========= So it seems that edje tries to delete an invalid eina_share_common string (is this a bug that should be fixed or is it theme-dependent?), and so the "node" pointer in eina share is not valid... However eina never checks for its validity, so it seg-faults... The attached patch fix this issue, setting the node to null when its magic is not valid, and then always checking for its validity. Is this fine? Full stack trace: #0 eina_share_common_del (share=0x65c810, str=0x7ffff1219150 "5hhu %5hu '%s'\n") at eina_share_common.c:858 #1 0x00007ffff120e047 in eina_stringshare_del (str=0x7ffff1219150 "5hhu %5hu '%s'\n") at eina_stringshare.c:632 #2 0x00007ffff1e1f7bc in _edje_text_recalc_apply (ed=0x95b900, ep=0x70c3a0, params=0x70c500, chosen_desc=<value optimized out>) at edje_text.c:556 #3 0x00007ffff1de402d in _edje_part_recalc (ed=0x95b900, ep=0x70c3a0, flags=3) at edje_calc.c:2007 #4 0x00007ffff1de4d86 in _edje_recalc_do (ed=0x95b900) at edje_calc.c:268 #5 0x00007ffff1e25c7d in edje_object_part_swallow (obj=<value optimized out>, part=0x7fffe001484c "elm.swallow.icon", obj_swallow=0x7fffe0017860) at edje_util.c:2300 #6 0x00007ffff1b5d5fc in _item_realize (it=0x7fffe0016ed0, in=10, calc=1) at elm_genlist.c:1489 #7 0x00007ffff1b5db89 in _item_block_recalc (itb=0x95b6a0, in=<value optimized out>, qadd=<value optimized out>, norender=<value optimized out>) at elm_genlist.c:1609 #8 0x00007ffff1b5e329 in _queue_proecess (wd=0x721b70, norender=<value optimized out>) at elm_genlist.c:2425 #9 0x00007ffff1b5e567 in _item_queue (wd=0x721b70, it=<value optimized out>) at elm_genlist.c:2476 #10 0x00007ffff1b5ead9 in elm_genlist_item_append (obj=<value optimized out>, itc=0x7ffff2977040, data=0x8fed90, parent=0x0, flags=ELM_GENLIST_ITEM_NONE, func=<value optimized out>, func_data=0x0) at elm_genlist.c:2528 [eina-share-common-del-check-for-node.patch text/x-patch (1.2KB)] Index: src/lib/eina_share_common.c =================================================================== --- src/lib/eina_share_common.c(revisione 55018) +++ src/lib/eina_share_common.c(copia locale) @@ -558,7 +558,7 @@ const size_t offset = offsetof(Eina_Share_Common_Node, str); node = (Eina_Share_Common_Node *)(str - offset); - EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, ); + EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL); return node; (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */ @@ -821,6 +821,7 @@ SHARE_COMMON_LOCK_BIG(); node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) return str; node->references++; DBG("str=%p refs=%u", str, node->references); @@ -847,6 +848,9 @@ SHARE_COMMON_LOCK_BIG(); node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) + return; + slen = node->length; eina_share_common_population_del(share, slen); if (node->references > 1) @@ -901,6 +905,7 @@ return -1; node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) return 0; return node->length; } SVN revision: 55265
2010-12-04 19:14:03 -08:00
EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL);
return node;
(void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */
}
static Eina_Bool
2010-07-27 19:37:05 -07:00
eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__,
Eina_Share_Common_Head *head,
struct dumpinfo *fdata)
{
Eina_Share_Common_Node *node;
fdata->used += sizeof(Eina_Share_Common_Head);
for (node = head->head; node; node = node->next)
{
2010-07-27 19:37:05 -07:00
printf("DDD: %5i %5i ", node->length, node->references);
printf("'%.*s'\n", node->length, ((char *)node) + sizeof(Eina_Share_Common_Node));
2010-07-27 19:37:05 -07:00
fdata->used += sizeof(Eina_Share_Common_Node);
fdata->used += node->length;
fdata->saved += (node->references - 1) * node->length;
fdata->dups += node->references - 1;
fdata->unique++;
}
return EINA_TRUE;
}
/**
* @endcond
*/
/*============================================================================*
2010-07-27 19:37:05 -07:00
* Global *
*============================================================================*/
/**
* @internal
* @brief Initialize the share_common module.
*
* @return #EINA_TRUE on success, #EINA_FALSE on failure.
*
* This function sets up the share_common module of Eina. It is called by
* eina_init().
*
* @see eina_init()
*/
Eina_Bool
2010-07-27 19:37:05 -07:00
eina_share_common_init(Eina_Share **_share,
Eina_Magic node_magic,
const char *node_magic_STR)
{
Eina_Share *share;
share = *_share = calloc(sizeof(Eina_Share), 1);
if (!share) goto on_error;
2010-07-27 19:37:05 -07:00
share->share = calloc(1, sizeof(Eina_Share_Common));
if (!share->share) goto on_error;
2010-07-27 19:37:05 -07:00
share->node_magic = node_magic;
2010-07-27 19:37:05 -07:00
#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
EMS(EINA_MAGIC_SHARE);
EMS(EINA_MAGIC_SHARE_HEAD);
EMS(node_magic);
#undef EMS
EINA_MAGIC_SET(share->share, EINA_MAGIC_SHARE);
_eina_share_common_population_init(share);
/* below is the common part among other all eina_share_common user */
if (_eina_share_common_count++ != 0)
return EINA_TRUE;
eina_lock_new(&_mutex_big);
return EINA_TRUE;
on_error:
_eina_share_common_count--;
return EINA_FALSE;
}
/**
* @internal
* @brief Shut down the share_common module.
*
* @return #EINA_TRUE on success, #EINA_FALSE on failure.
*
* This function shuts down the share_common module set up by
* eina_share_common_init(). It is called by eina_shutdown().
*
* @see eina_shutdown()
*/
Eina_Bool
eina_share_common_shutdown(Eina_Share **_share)
{
unsigned int i;
Eina_Share *share = *_share;
eina_lock_take(&_mutex_big);
_eina_share_common_population_stats(share);
/* remove any string still in the table */
for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
{
2010-07-27 19:37:05 -07:00
eina_rbtree_delete(EINA_RBTREE_GET(
share->share->buckets[i]),
EINA_RBTREE_FREE_CB(
_eina_share_common_head_free), NULL);
share->share->buckets[i] = NULL;
}
MAGIC_FREE(share->share);
_eina_share_common_population_shutdown(share);
eina_lock_release(&_mutex_big);
free(*_share);
*_share = NULL;
/* below is the common part among other all eina_share_common user */
if (--_eina_share_common_count != 0)
return EINA_TRUE;
eina_lock_free(&_mutex_big);
return EINA_TRUE;
}
#ifdef EFL_HAVE_THREADS
/**
* @internal
* @brief Activate the share_common mutexes.
*
* This function activate the mutexes in the eina share_common module. It is called by
* eina_threads_init().
*
* @see eina_threads_init()
*/
void
eina_share_common_threads_init(void)
{
_share_common_threads_activated = EINA_TRUE;
}
/**
* @internal
* @brief Shut down the share_common mutexes.
*
* This function shuts down the mutexes in the share_common module.
* It is called by eina_threads_shutdown().
*
* @see eina_threads_shutdown()
*/
void
eina_share_common_threads_shutdown(void)
{
_share_common_threads_activated = EINA_FALSE;
}
#endif
/*============================================================================*
2010-07-27 19:37:05 -07:00
* API *
*============================================================================*/
/**
* @cond LOCAL
*/
const char *
2010-07-27 19:37:05 -07:00
eina_share_common_add_length(Eina_Share *share,
const char *str,
unsigned int slen,
unsigned int null_size)
{
Eina_Share_Common_Head **p_bucket, *ed;
Eina_Share_Common_Node *el;
int hash_num, hash;
2010-07-27 19:37:05 -07:00
if (!str)
return NULL;
eina_share_common_population_add(share, slen);
if (slen <= 0)
2010-07-27 19:37:05 -07:00
return NULL;
hash = eina_hash_superfast(str, slen);
hash_num = hash & 0xFF;
hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
eina_lock_take(&_mutex_big);
p_bucket = share->share->buckets + hash_num;
ed = _eina_share_common_find_hash(*p_bucket, hash);
if (!ed)
{
2010-07-27 19:37:05 -07:00
const char *s = _eina_share_common_add_head(share,
p_bucket,
hash,
str,
slen,
null_size);
eina_lock_release(&_mutex_big);
return s;
}
EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), NULL);
el = _eina_share_common_head_find(ed, str, slen);
if (el)
{
2010-07-27 19:37:05 -07:00
EINA_MAGIC_CHECK_SHARE_COMMON_NODE(el,
share->node_magic,
eina_lock_release(&_mutex_big));
2010-07-27 19:37:05 -07:00
el->references++;
eina_lock_release(&_mutex_big);
2010-07-27 19:37:05 -07:00
return el->str;
}
el = _eina_share_common_node_alloc(slen, null_size);
if (!el)
{
eina_lock_release(&_mutex_big);
2010-07-27 19:37:05 -07:00
return NULL;
}
_eina_share_common_node_init(el, str, slen, null_size, share->node_magic);
el->next = ed->head;
ed->head = el;
_eina_share_common_population_head_add(share, ed);
eina_lock_release(&_mutex_big);
return el->str;
}
const char *
eina_share_common_ref(Eina_Share *share, const char *str)
{
Eina_Share_Common_Node *node;
2010-07-27 19:37:05 -07:00
if (!str)
return NULL;
eina_lock_take(&_mutex_big);
node = _eina_share_common_node_from_str(str, share->node_magic);
if (!node)
{
eina_lock_release(&_mutex_big);
return str;
}
node->references++;
eina_lock_release(&_mutex_big);
eina_share_common_population_add(share, node->length);
return str;
}
Eina_Bool
eina_share_common_del(Eina_Share *share, const char *str)
{
unsigned int slen;
Eina_Share_Common_Head *ed;
Eina_Share_Common_Head **p_bucket;
Eina_Share_Common_Node *node;
int hash_num, hash;
2010-07-27 19:37:05 -07:00
if (!str)
return EINA_TRUE;
eina_lock_take(&_mutex_big);
node = _eina_share_common_node_from_str(str, share->node_magic);
SVN revision: 3 Subject: [E-devel] [PATCH] eina share common check for node type Hello, recentely I've been experiencing a lot of segfaults when running an Elementary application which uses a genlist with some swallowed parts in which I put some elm icons (png files). When running it I often get crashes... Debugging it I found this: ========= CRI<14207>: eina_share_common.c:561 _eina_share_common_node_from_str() *** Eina Magic Check Failed !!! Input handle is wrong type Expected: 98761254 - Eina Stringshare Node Supplied: 6e657070 - (unknown) *** NAUGHTY PROGRAMMER!!! *** SPANK SPANK SPANK!!! *** Now go fix your code. Tut tut tut! //DEBUG: Node referencies 622869060 (slen: 1145307236) Program received signal SIGSEGV, Segmentation fault. eina_share_common_del (share=0x65c810, str=0x7ffff1219150 "5hhu %5hu '% s'\n") at eina_share_common.c:858 858 node->references--; ========= So it seems that edje tries to delete an invalid eina_share_common string (is this a bug that should be fixed or is it theme-dependent?), and so the "node" pointer in eina share is not valid... However eina never checks for its validity, so it seg-faults... The attached patch fix this issue, setting the node to null when its magic is not valid, and then always checking for its validity. Is this fine? Full stack trace: #0 eina_share_common_del (share=0x65c810, str=0x7ffff1219150 "5hhu %5hu '%s'\n") at eina_share_common.c:858 #1 0x00007ffff120e047 in eina_stringshare_del (str=0x7ffff1219150 "5hhu %5hu '%s'\n") at eina_stringshare.c:632 #2 0x00007ffff1e1f7bc in _edje_text_recalc_apply (ed=0x95b900, ep=0x70c3a0, params=0x70c500, chosen_desc=<value optimized out>) at edje_text.c:556 #3 0x00007ffff1de402d in _edje_part_recalc (ed=0x95b900, ep=0x70c3a0, flags=3) at edje_calc.c:2007 #4 0x00007ffff1de4d86 in _edje_recalc_do (ed=0x95b900) at edje_calc.c:268 #5 0x00007ffff1e25c7d in edje_object_part_swallow (obj=<value optimized out>, part=0x7fffe001484c "elm.swallow.icon", obj_swallow=0x7fffe0017860) at edje_util.c:2300 #6 0x00007ffff1b5d5fc in _item_realize (it=0x7fffe0016ed0, in=10, calc=1) at elm_genlist.c:1489 #7 0x00007ffff1b5db89 in _item_block_recalc (itb=0x95b6a0, in=<value optimized out>, qadd=<value optimized out>, norender=<value optimized out>) at elm_genlist.c:1609 #8 0x00007ffff1b5e329 in _queue_proecess (wd=0x721b70, norender=<value optimized out>) at elm_genlist.c:2425 #9 0x00007ffff1b5e567 in _item_queue (wd=0x721b70, it=<value optimized out>) at elm_genlist.c:2476 #10 0x00007ffff1b5ead9 in elm_genlist_item_append (obj=<value optimized out>, itc=0x7ffff2977040, data=0x8fed90, parent=0x0, flags=ELM_GENLIST_ITEM_NONE, func=<value optimized out>, func_data=0x0) at elm_genlist.c:2528 [eina-share-common-del-check-for-node.patch text/x-patch (1.2KB)] Index: src/lib/eina_share_common.c =================================================================== --- src/lib/eina_share_common.c(revisione 55018) +++ src/lib/eina_share_common.c(copia locale) @@ -558,7 +558,7 @@ const size_t offset = offsetof(Eina_Share_Common_Node, str); node = (Eina_Share_Common_Node *)(str - offset); - EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, ); + EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL); return node; (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */ @@ -821,6 +821,7 @@ SHARE_COMMON_LOCK_BIG(); node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) return str; node->references++; DBG("str=%p refs=%u", str, node->references); @@ -847,6 +848,9 @@ SHARE_COMMON_LOCK_BIG(); node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) + return; + slen = node->length; eina_share_common_population_del(share, slen); if (node->references > 1) @@ -901,6 +905,7 @@ return -1; node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) return 0; return node->length; } SVN revision: 55265
2010-12-04 19:14:03 -08:00
if (!node)
goto on_error;
SVN revision: 3 Subject: [E-devel] [PATCH] eina share common check for node type Hello, recentely I've been experiencing a lot of segfaults when running an Elementary application which uses a genlist with some swallowed parts in which I put some elm icons (png files). When running it I often get crashes... Debugging it I found this: ========= CRI<14207>: eina_share_common.c:561 _eina_share_common_node_from_str() *** Eina Magic Check Failed !!! Input handle is wrong type Expected: 98761254 - Eina Stringshare Node Supplied: 6e657070 - (unknown) *** NAUGHTY PROGRAMMER!!! *** SPANK SPANK SPANK!!! *** Now go fix your code. Tut tut tut! //DEBUG: Node referencies 622869060 (slen: 1145307236) Program received signal SIGSEGV, Segmentation fault. eina_share_common_del (share=0x65c810, str=0x7ffff1219150 "5hhu %5hu '% s'\n") at eina_share_common.c:858 858 node->references--; ========= So it seems that edje tries to delete an invalid eina_share_common string (is this a bug that should be fixed or is it theme-dependent?), and so the "node" pointer in eina share is not valid... However eina never checks for its validity, so it seg-faults... The attached patch fix this issue, setting the node to null when its magic is not valid, and then always checking for its validity. Is this fine? Full stack trace: #0 eina_share_common_del (share=0x65c810, str=0x7ffff1219150 "5hhu %5hu '%s'\n") at eina_share_common.c:858 #1 0x00007ffff120e047 in eina_stringshare_del (str=0x7ffff1219150 "5hhu %5hu '%s'\n") at eina_stringshare.c:632 #2 0x00007ffff1e1f7bc in _edje_text_recalc_apply (ed=0x95b900, ep=0x70c3a0, params=0x70c500, chosen_desc=<value optimized out>) at edje_text.c:556 #3 0x00007ffff1de402d in _edje_part_recalc (ed=0x95b900, ep=0x70c3a0, flags=3) at edje_calc.c:2007 #4 0x00007ffff1de4d86 in _edje_recalc_do (ed=0x95b900) at edje_calc.c:268 #5 0x00007ffff1e25c7d in edje_object_part_swallow (obj=<value optimized out>, part=0x7fffe001484c "elm.swallow.icon", obj_swallow=0x7fffe0017860) at edje_util.c:2300 #6 0x00007ffff1b5d5fc in _item_realize (it=0x7fffe0016ed0, in=10, calc=1) at elm_genlist.c:1489 #7 0x00007ffff1b5db89 in _item_block_recalc (itb=0x95b6a0, in=<value optimized out>, qadd=<value optimized out>, norender=<value optimized out>) at elm_genlist.c:1609 #8 0x00007ffff1b5e329 in _queue_proecess (wd=0x721b70, norender=<value optimized out>) at elm_genlist.c:2425 #9 0x00007ffff1b5e567 in _item_queue (wd=0x721b70, it=<value optimized out>) at elm_genlist.c:2476 #10 0x00007ffff1b5ead9 in elm_genlist_item_append (obj=<value optimized out>, itc=0x7ffff2977040, data=0x8fed90, parent=0x0, flags=ELM_GENLIST_ITEM_NONE, func=<value optimized out>, func_data=0x0) at elm_genlist.c:2528 [eina-share-common-del-check-for-node.patch text/x-patch (1.2KB)] Index: src/lib/eina_share_common.c =================================================================== --- src/lib/eina_share_common.c(revisione 55018) +++ src/lib/eina_share_common.c(copia locale) @@ -558,7 +558,7 @@ const size_t offset = offsetof(Eina_Share_Common_Node, str); node = (Eina_Share_Common_Node *)(str - offset); - EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, ); + EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL); return node; (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */ @@ -821,6 +821,7 @@ SHARE_COMMON_LOCK_BIG(); node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) return str; node->references++; DBG("str=%p refs=%u", str, node->references); @@ -847,6 +848,9 @@ SHARE_COMMON_LOCK_BIG(); node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) + return; + slen = node->length; eina_share_common_population_del(share, slen); if (node->references > 1) @@ -901,6 +905,7 @@ return -1; node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) return 0; return node->length; } SVN revision: 55265
2010-12-04 19:14:03 -08:00
slen = node->length;
eina_share_common_population_del(share, slen);
if (node->references > 1)
{
2010-07-27 19:37:05 -07:00
node->references--;
eina_lock_release(&_mutex_big);
return EINA_TRUE;
}
node->references = 0;
hash = eina_hash_superfast(str, slen);
hash_num = hash & 0xFF;
hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
p_bucket = share->share->buckets + hash_num;
ed = _eina_share_common_find_hash(*p_bucket, hash);
if (!ed)
2010-07-27 19:37:05 -07:00
goto on_error;
EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), EINA_FALSE);
if (!_eina_share_common_head_remove_node(ed, node))
2010-07-27 19:37:05 -07:00
goto on_error;
if (node != &ed->builtin_node)
2010-07-27 19:37:05 -07:00
MAGIC_FREE(node);
if (!ed->head)
2010-07-27 19:37:05 -07:00
_eina_share_common_del_head(p_bucket, ed);
else
2010-07-27 19:37:05 -07:00
_eina_share_common_population_head_del(share, ed);
eina_lock_release(&_mutex_big);
return EINA_TRUE;
2010-07-27 19:37:05 -07:00
on_error:
eina_lock_release(&_mutex_big);
/* possible segfault happened before here, but... */
return EINA_FALSE;
}
int
eina_share_common_length(__UNUSED__ Eina_Share *share, const char *str)
{
const Eina_Share_Common_Node *node;
if (!str)
2010-07-27 19:37:05 -07:00
return -1;
node = _eina_share_common_node_from_str(str, share->node_magic);
SVN revision: 3 Subject: [E-devel] [PATCH] eina share common check for node type Hello, recentely I've been experiencing a lot of segfaults when running an Elementary application which uses a genlist with some swallowed parts in which I put some elm icons (png files). When running it I often get crashes... Debugging it I found this: ========= CRI<14207>: eina_share_common.c:561 _eina_share_common_node_from_str() *** Eina Magic Check Failed !!! Input handle is wrong type Expected: 98761254 - Eina Stringshare Node Supplied: 6e657070 - (unknown) *** NAUGHTY PROGRAMMER!!! *** SPANK SPANK SPANK!!! *** Now go fix your code. Tut tut tut! //DEBUG: Node referencies 622869060 (slen: 1145307236) Program received signal SIGSEGV, Segmentation fault. eina_share_common_del (share=0x65c810, str=0x7ffff1219150 "5hhu %5hu '% s'\n") at eina_share_common.c:858 858 node->references--; ========= So it seems that edje tries to delete an invalid eina_share_common string (is this a bug that should be fixed or is it theme-dependent?), and so the "node" pointer in eina share is not valid... However eina never checks for its validity, so it seg-faults... The attached patch fix this issue, setting the node to null when its magic is not valid, and then always checking for its validity. Is this fine? Full stack trace: #0 eina_share_common_del (share=0x65c810, str=0x7ffff1219150 "5hhu %5hu '%s'\n") at eina_share_common.c:858 #1 0x00007ffff120e047 in eina_stringshare_del (str=0x7ffff1219150 "5hhu %5hu '%s'\n") at eina_stringshare.c:632 #2 0x00007ffff1e1f7bc in _edje_text_recalc_apply (ed=0x95b900, ep=0x70c3a0, params=0x70c500, chosen_desc=<value optimized out>) at edje_text.c:556 #3 0x00007ffff1de402d in _edje_part_recalc (ed=0x95b900, ep=0x70c3a0, flags=3) at edje_calc.c:2007 #4 0x00007ffff1de4d86 in _edje_recalc_do (ed=0x95b900) at edje_calc.c:268 #5 0x00007ffff1e25c7d in edje_object_part_swallow (obj=<value optimized out>, part=0x7fffe001484c "elm.swallow.icon", obj_swallow=0x7fffe0017860) at edje_util.c:2300 #6 0x00007ffff1b5d5fc in _item_realize (it=0x7fffe0016ed0, in=10, calc=1) at elm_genlist.c:1489 #7 0x00007ffff1b5db89 in _item_block_recalc (itb=0x95b6a0, in=<value optimized out>, qadd=<value optimized out>, norender=<value optimized out>) at elm_genlist.c:1609 #8 0x00007ffff1b5e329 in _queue_proecess (wd=0x721b70, norender=<value optimized out>) at elm_genlist.c:2425 #9 0x00007ffff1b5e567 in _item_queue (wd=0x721b70, it=<value optimized out>) at elm_genlist.c:2476 #10 0x00007ffff1b5ead9 in elm_genlist_item_append (obj=<value optimized out>, itc=0x7ffff2977040, data=0x8fed90, parent=0x0, flags=ELM_GENLIST_ITEM_NONE, func=<value optimized out>, func_data=0x0) at elm_genlist.c:2528 [eina-share-common-del-check-for-node.patch text/x-patch (1.2KB)] Index: src/lib/eina_share_common.c =================================================================== --- src/lib/eina_share_common.c(revisione 55018) +++ src/lib/eina_share_common.c(copia locale) @@ -558,7 +558,7 @@ const size_t offset = offsetof(Eina_Share_Common_Node, str); node = (Eina_Share_Common_Node *)(str - offset); - EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, ); + EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, node = NULL); return node; (void) node_magic; /* When magic are disable, node_magic is unused, this remove a warning. */ @@ -821,6 +821,7 @@ SHARE_COMMON_LOCK_BIG(); node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) return str; node->references++; DBG("str=%p refs=%u", str, node->references); @@ -847,6 +848,9 @@ SHARE_COMMON_LOCK_BIG(); node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) + return; + slen = node->length; eina_share_common_population_del(share, slen); if (node->references > 1) @@ -901,6 +905,7 @@ return -1; node = _eina_share_common_node_from_str(str, share->node_magic); + if (!node) return 0; return node->length; } SVN revision: 55265
2010-12-04 19:14:03 -08:00
if (!node) return 0;
return node->length;
}
void
2010-07-27 19:37:05 -07:00
eina_share_common_dump(Eina_Share *share, void (*additional_dump)(
struct dumpinfo *), int used)
{
Eina_Iterator *it;
unsigned int i;
struct dumpinfo di;
2010-07-27 19:37:05 -07:00
if (!share)
return;
di.used = used;
di.saved = 0;
di.dups = 0;
di.unique = 0;
printf("DDD: len ref string\n");
printf("DDD:-------------------\n");
eina_lock_take(&_mutex_big);
for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
{
2010-07-27 19:37:05 -07:00
if (!share->share->buckets[i])
{
continue; // printf("DDD: BUCKET # %i (HEAD=%i, NODE=%i)\n", i,
}
2010-07-27 19:37:05 -07:00
// sizeof(Eina_Share_Common_Head), sizeof(Eina_Share_Common_Node));
2010-07-27 19:37:05 -07:00
it = eina_rbtree_iterator_prefix(
(Eina_Rbtree *)share->share->buckets[i]);
eina_iterator_foreach(it, EINA_EACH_CB(eina_iterator_array_check), &di);
2010-07-27 19:37:05 -07:00
eina_iterator_free(it);
}
if (additional_dump)
additional_dump(&di);
2010-07-27 19:37:05 -07:00
#ifdef EINA_SHARE_COMMON_USAGE
/* One character strings are not counted in the hash. */
di.saved += share->population_group[0].count * sizeof(char);
di.saved += share->population_group[1].count * sizeof(char) * 2;
#endif
printf("DDD:-------------------\n");
printf("DDD: usage (bytes) = %i, saved = %i (%3.0f%%)\n",
2010-07-27 19:37:05 -07:00
di.used, di.saved, di.used ? (di.saved * 100.0 / di.used) : 0.0);
printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n",
2010-07-27 19:37:05 -07:00
di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0);
#ifdef EINA_SHARE_COMMON_USAGE
2010-07-27 19:37:05 -07:00
printf("DDD: Allocated strings: %i\n", share->population.count);
printf("DDD: Max allocated strings: %i\n", share->population.max);
2010-07-27 19:37:05 -07:00
for (i = 0;
i < sizeof (share->population_group) /
sizeof (share->population_group[0]);
++i)
fprintf(stderr,
"DDD: %i strings of length %u, max strings: %i\n",
2010-07-27 19:37:05 -07:00
share->population_group[i].count,
i,
share->population_group[i].max);
#endif
eina_lock_release(&_mutex_big);
}
/**
* @endcond
*/