Eo: protect against recursive object destruction calls, fixes T1741

Summary:
    Eo: semantic obj->del replaced by obj->destructed
    Eo: protect against recursive object destruction calls
    Eo: add tests for bfada4b

Reviewers: JackDanielZ, tasn

Reviewed By: tasn

Subscribers: cedric

Maniphest Tasks: T1741

Differential Revision: https://phab.enlightenment.org/D1675

Fixes T1741

@fix
This commit is contained in:
Jérémy Zurcher 2014-11-18 15:24:39 +00:00 committed by Tom Hacohen
parent ee3bcaf71d
commit 18ceed4daf
6 changed files with 80 additions and 6 deletions

View File

@ -121,6 +121,7 @@ tests/eo/suite/eo_suite.h \
tests/eo/suite/eo_error_msgs.h \
tests/eo/suite/eo_error_msgs.c \
tests/eo/suite/eo_test_class_errors.c \
tests/eo/suite/eo_test_class_behaviour_errors.c \
tests/eo/suite/eo_test_call_errors.c \
tests/eo/suite/eo_test_general.c \
tests/eo/suite/eo_test_value.c \

View File

@ -1855,7 +1855,7 @@ eo_destructed_is(const Eo *obj_id)
{
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE);
return obj->del;
return obj->destructed;
}
EAPI void
@ -1876,7 +1876,7 @@ eo_manual_free(Eo *obj_id)
return EINA_FALSE;
}
if (!obj->del)
if (!obj->destructed)
{
ERR("Tried deleting the object %p while still referenced(%d).", obj_id, obj->refcount);
return EINA_FALSE;

View File

@ -104,7 +104,8 @@ struct _Eo_Object
Eina_Bool finalized:1;
Eina_Bool composite:1;
Eina_Bool del:1;
Eina_Bool del_triggered:1;
Eina_Bool destructed:1;
Eina_Bool manual_free:1;
};
@ -235,7 +236,7 @@ _eo_del_internal(const char *file, int line, _Eo_Object *obj)
}
}
obj->del = EINA_TRUE;
obj->destructed = EINA_TRUE;
obj->refcount--;
}
@ -278,9 +279,16 @@ _eo_unref(_Eo_Object *obj)
--(obj->refcount);
if (obj->refcount == 0)
{
if (obj->del)
if (obj->del_triggered)
{
ERR("Object %p already deleted.", obj);
ERR("Object %p deletion already triggered. You wrongly call eo_unref() within a destructor.", obj);
return;
}
obj->del_triggered = EINA_TRUE;
if (obj->destructed)
{
ERR("Object %p already destructed.", obj);
return;
}

View File

@ -20,6 +20,7 @@ static const Eo_Test_Case etc[] = {
{ "Eo init", eo_test_init },
{ "Eo general", eo_test_general },
{ "Eo class errors", eo_test_class_errors },
{ "Eo class behaviour errors", eo_test_class_behaviour_errors },
{ "Eo call errors", eo_test_call_errors },
{ "Eo eina value", eo_test_value },
{ "Eo threaded eo calls", eo_test_threaded_calls },

View File

@ -6,6 +6,7 @@
void eo_test_init(TCase *tc);
void eo_test_general(TCase *tc);
void eo_test_class_errors(TCase *tc);
void eo_test_class_behaviour_errors(TCase *tc);
void eo_test_call_errors(TCase *tc);
void eo_test_value(TCase *tc);
void eo_test_threaded_calls(TCase *tc);

View File

@ -0,0 +1,63 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include "Eo.h"
#include "eo_suite.h"
#include "eo_error_msgs.h"
#include "eo_test_class_simple.h"
static struct log_ctx ctx;
const Eo_Class *klass;
static void _destructor_unref(Eo *obj, void *class_data EINA_UNUSED)
{
eo_do_super(obj, klass, eo_destructor());
/* this triggers an eo stack overflow if not correctly protected */
eo_unref(obj);
}
START_TEST(eo_destructor_unref)
{
eo_init();
eina_log_print_cb_set(eo_test_print_cb, &ctx);
static Eo_Op_Description op_descs [] = {
EO_OP_FUNC_OVERRIDE(eo_destructor, _destructor_unref),
EO_OP_SENTINEL
};
static Eo_Class_Description class_desc = {
EO_VERSION,
"Simple",
EO_CLASS_TYPE_REGULAR,
EO_CLASS_DESCRIPTION_OPS(op_descs),
NULL,
0,
NULL,
NULL
};
klass = eo_class_new(&class_desc, SIMPLE_CLASS, NULL);
fail_unless(klass);
Eo *obj = eo_add(klass, NULL);
fail_unless(obj);
TEST_EO_ERROR("_eo_unref", "Object %p deletion already triggered. You wrongly call eo_unref() within a destructor.");
eo_unref(obj);
eina_log_print_cb_set(eina_log_print_cb_stderr, NULL);
eo_shutdown();
}
END_TEST
void eo_test_class_behaviour_errors(TCase *tc)
{
tcase_add_test(tc, eo_destructor_unref);
}