From 18ceed4daf31d2f19261e0fe018c870581357ed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Zurcher?= Date: Tue, 18 Nov 2014 15:24:39 +0000 Subject: [PATCH] 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 --- src/Makefile_Eo.am | 1 + src/lib/eo/eo.c | 4 +- src/lib/eo/eo_private.h | 16 +++-- src/tests/eo/suite/eo_suite.c | 1 + src/tests/eo/suite/eo_suite.h | 1 + .../eo/suite/eo_test_class_behaviour_errors.c | 63 +++++++++++++++++++ 6 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 src/tests/eo/suite/eo_test_class_behaviour_errors.c diff --git a/src/Makefile_Eo.am b/src/Makefile_Eo.am index 306c8c3623..1b3ea4a75d 100644 --- a/src/Makefile_Eo.am +++ b/src/Makefile_Eo.am @@ -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 \ diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index 37dae75deb..cc1f8b9f02 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -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; diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h index c652271dd6..7ea501450f 100644 --- a/src/lib/eo/eo_private.h +++ b/src/lib/eo/eo_private.h @@ -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; } diff --git a/src/tests/eo/suite/eo_suite.c b/src/tests/eo/suite/eo_suite.c index 42c6645156..90f557745d 100644 --- a/src/tests/eo/suite/eo_suite.c +++ b/src/tests/eo/suite/eo_suite.c @@ -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 }, diff --git a/src/tests/eo/suite/eo_suite.h b/src/tests/eo/suite/eo_suite.h index 94d88bd1fe..ba07799bc9 100644 --- a/src/tests/eo/suite/eo_suite.h +++ b/src/tests/eo/suite/eo_suite.h @@ -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); diff --git a/src/tests/eo/suite/eo_test_class_behaviour_errors.c b/src/tests/eo/suite/eo_test_class_behaviour_errors.c new file mode 100644 index 0000000000..1bd0e15c76 --- /dev/null +++ b/src/tests/eo/suite/eo_test_class_behaviour_errors.c @@ -0,0 +1,63 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#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); +}