From d889da6b12e6123073edb54d766c9af1fc6db822 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Tue, 29 Sep 2015 00:45:34 +0100 Subject: [PATCH] Eo legacy events: Fix broken callback comparison Commit 37f84b7e966372384e2dfe5d191a6f907a17962e introduced a few changes to the callback matching mechanism that made it so sometimes callbacks would be triggered for the wrong events. The problem was there because of the support for legacy events that forces to do string comparison instead of the usual pointer comparison. We should only do string comparison when we are certain one of the callbacks is a legacy generated one. Regression tests will follow tomorrow. Way too late here for that. Thanks to cedric for reporting. --- src/lib/eo/Eo.h | 2 ++ src/lib/eo/eo_base_class.c | 39 +++++++++++++++++++++++++--- src/tests/eo/suite/eo_test_general.c | 4 +-- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index 3f551f481d..66be6ff96b 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -919,6 +919,8 @@ typedef void (*eo_key_data_free_func)(void *); /** * Don't use. + * The values of the returned event structure are also internal, don't assume + * anything about them. * @internal */ EAPI const Eo_Event_Description *eo_base_legacy_only_event_description_get(const char *_event_name); diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index f85aa4e78a..f0a4030af3 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -401,11 +401,16 @@ _wref_destruct(Eo_Base_Data *pd) /* XXX: Legacy support, remove when legacy is dead. */ static Eina_Hash *_legacy_events_hash = NULL; +#define _LEGACY_EVENT_FIRST_CHAR 1 EAPI const Eo_Event_Description * eo_base_legacy_only_event_description_get(const char *_event_name) { - Eina_Stringshare *event_name = eina_stringshare_add(_event_name); + char buf[1024]; + buf[0] = _LEGACY_EVENT_FIRST_CHAR; /* Encode it's a legacy event */ + strncpy(buf + 1, _event_name, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + Eina_Stringshare *event_name = eina_stringshare_add(buf); Eo_Event_Description *event_desc = eina_hash_find(_legacy_events_hash, event_name); if (!event_desc) { @@ -421,6 +426,26 @@ eo_base_legacy_only_event_description_get(const char *_event_name) return event_desc; } +static Eina_Bool +_legacy_event_desc_is(const Eo_Event_Description *desc) +{ + return (desc->name[0] == _LEGACY_EVENT_FIRST_CHAR); +} + +/* Also supports non legacy. */ +static const char * +_legacy_event_desc_name_get(const Eo_Event_Description *desc) +{ + if (_legacy_event_desc_is(desc)) + { + return desc->name + 1; + } + else + { + return desc->name; + } +} + static void _legacy_events_hash_free_cb(void *_desc) { @@ -641,13 +666,19 @@ _cb_desc_match(const Eo_Event_Description *a, const Eo_Event_Description *b) if (!a) return EINA_FALSE; - if (a == b) + if (_legacy_event_desc_is(a) && _legacy_event_desc_is(b)) { - return EINA_TRUE; + return (a->name == b->name); + } + else if (_legacy_event_desc_is(a) || _legacy_event_desc_is(b)) + { + const char *aname = _legacy_event_desc_name_get(a); + const char *bname = _legacy_event_desc_name_get(b); + return !strcmp(aname, bname); } else { - return !strcmp(a->name, b->name); + return (a == b); } } diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c index ccd6af2b45..b483a808b1 100644 --- a/src/tests/eo/suite/eo_test_general.c +++ b/src/tests/eo/suite/eo_test_general.c @@ -125,12 +125,12 @@ START_TEST(eo_signals) { const Eo_Event_Description *a_desc = eo_base_legacy_only_event_description_get("a,changed"); fail_if(!a_desc); - ck_assert_str_eq(a_desc->name, "a,changed"); + ck_assert_str_eq(a_desc->name, "\x01" "a,changed"); fail_if(a_desc == EV_A_CHANGED); const Eo_Event_Description *bad_desc = eo_base_legacy_only_event_description_get("bad"); fail_if(!bad_desc); - ck_assert_str_eq(bad_desc->name, "bad"); + ck_assert_str_eq(bad_desc->name, "\x01" "bad"); /* Call Eo event with legacy and non-legacy callbacks. */ _eo_signals_cb_current = 0;