From 2e96b5074dfb4212e72701db63de13222b9aa9b3 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Wed, 15 Feb 2017 14:43:35 +0900 Subject: [PATCH] eo_debug: Improve dangling xref debug logs even more In case of manual free, as is heavily used by Evas, we can't really print an ERR if there are still references before free has been called. This may not be ideal from a pure EO point of view but considering how Evas uses manual free this is the best solution to avoid polluting debug logs. --- src/lib/eo/eo.c | 39 +++++++++++++++++++++++++++++++---- src/lib/eo/eo_private.h | 55 +++++++++++++++++++++++++++---------------------- 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index 3722152..182a3a4 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -965,16 +965,47 @@ efl_reuse(const Eo *_obj) void -_eo_free(_Eo_Object *obj) +_eo_free(_Eo_Object *obj, Eina_Bool manual_free EINA_UNUSED) { _Efl_Class *klass = (_Efl_Class*) obj->klass; _eo_log_obj_free(obj); #ifdef EO_DEBUG - if (obj->datarefcount) + if (manual_free) { - ERR("Object %p data still referenced %d time(s).", obj, obj->datarefcount); + Eo *obj_id = _eo_obj_id_get(obj); + if (obj->datarefcount) + { + ERR("Object %p data still referenced %d time(s).", obj_id, obj->datarefcount); + } + while (obj->xrefs) + { + Eina_Inlist *nitr = obj->xrefs->next; + Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node); + ERR("Object %p is still referenced by object %p. Origin: %s:%d", + obj_id, xref->ref_obj, xref->file, xref->line); + eina_freeq_ptr_main_add(xref, free, sizeof(*xref)); + obj->xrefs = nitr; + } + while (obj->data_xrefs) + { + Eina_Inlist *nitr = obj->data_xrefs->next; + Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node); + if (obj_id == xref->ref_obj) + { + WRN("Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d", + obj_id, xref->data_klass, xref->file, xref->line); + } + else + { + ERR("Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d", + obj_id, xref->data_klass, xref->ref_obj, xref->file, xref->line); + } + + eina_freeq_ptr_main_add(xref, free, sizeof(*xref)); + obj->data_xrefs = nitr; + } } #endif if (_obj_is_override(obj)) @@ -2362,7 +2393,7 @@ efl_manual_free(Eo *obj_id) if (obj->manual_free == EINA_FALSE) goto err_manual_free; // rare to use goto to keep instruction cache cleaner if (!obj->destructed) goto err_not_destructed; - _eo_free(obj); + _eo_free(obj, EINA_TRUE); EO_OBJ_DONE(obj_id); return EINA_TRUE; diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h index 7a6ed69..658c79f 100644 --- a/src/lib/eo/eo_private.h +++ b/src/lib/eo/eo_private.h @@ -274,7 +274,7 @@ _obj_is_override(_Eo_Object *obj) return (obj->vtable != &obj->klass->vtable); } -void _eo_free(_Eo_Object *obj); +void _eo_free(_Eo_Object *obj, Eina_Bool manual_free); static inline _Eo_Object * _efl_ref(_Eo_Object *obj) @@ -322,38 +322,43 @@ _efl_unref_internal(_Eo_Object *obj, const char *func_name, const char *file, in obj->del_triggered = EINA_TRUE; _efl_del_internal(obj, func_name, file, line); -#ifdef EO_DEBUG - /* If for some reason it's not empty, clear it. */ - while (obj->xrefs) - { - ERR("in %s:%d: func '%s' obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.", file, line, func_name); - Eina_Inlist *nitr = obj->xrefs->next; - eina_freeq_ptr_main_add(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eo_Xref_Node), free, 0); - obj->xrefs = nitr; - } - while (obj->data_xrefs) + + if (EINA_LIKELY(!obj->manual_free)) { - Eina_Inlist *nitr = obj->data_xrefs->next; - Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node); +#ifdef EO_DEBUG + /* If for some reason it's not empty, clear it. */ Eo *obj_id = _eo_obj_id_get(obj); - if (obj_id == xref->ref_obj) + while (obj->xrefs) { - WRN("in %s:%d: func '%s' Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d", - file, line, func_name, obj_id, xref->data_klass, xref->file, xref->line); + Eina_Inlist *nitr = obj->xrefs->next; + Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node); + ERR("in %s:%d: func '%s' Object %p is still referenced by object %p. Origin: %s:%d", + file, line, func_name, obj_id, xref->ref_obj, xref->file, xref->line); + eina_freeq_ptr_main_add(xref, free, sizeof(*xref)); + obj->xrefs = nitr; } - else + while (obj->data_xrefs) { - ERR("in %s:%d: func '%s' Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d", - file, line, func_name, obj_id, xref->data_klass, xref->ref_obj, xref->file, xref->line); + Eina_Inlist *nitr = obj->data_xrefs->next; + Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node); + if (obj_id == xref->ref_obj) + { + WRN("in %s:%d: func '%s' Object %p still has a reference to its own data (subclass: %s). Origin: %s:%d", + file, line, func_name, obj_id, xref->data_klass, xref->file, xref->line); + } + else + { + ERR("in %s:%d: func '%s' Data of object %p (subclass: %s) is still referenced by object %p. Origin: %s:%d", + file, line, func_name, obj_id, xref->data_klass, xref->ref_obj, xref->file, xref->line); + } + + eina_freeq_ptr_main_add(xref, free, sizeof(*xref)); + obj->data_xrefs = nitr; } - - eina_freeq_ptr_main_add(xref, free, sizeof(*xref)); - obj->data_xrefs = nitr; - } #endif - if (!obj->manual_free) - _eo_free(obj); + _eo_free(obj, EINA_FALSE); + } else _efl_ref(obj); /* If we manual free, we keep a phantom ref. */ } -- 2.7.4