From: Suyeon Hwang Date: Thu, 26 Jan 2023 07:52:09 +0000 (+0900) Subject: Destroy RPC handle in ecore idler X-Git-Tag: accepted/tizen/unified/20230215.100739^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fe6372b41e69bf0a20720a722e929aa902b096c4;p=platform%2Fcore%2Fuifw%2Ftts.git Destroy RPC handle in ecore idler - Issue: Invoking tts_unprepare() in event callbacks is allowed and this may cause segmentation fault by destroying RPC handle in the callback which is invoked by RPC message. - Solution: The app can call tts_unprepare() in the callback. However, this invocation may cause segmentation fault by destroying the RPC handle in the callback of the RPC handle itself. To solve this issue, this patch fixes the RPC handle destruction logic. Through this patch, the client lib will destroy the handle in ecore idler callback. This behavior can avoid wrong handle destruction. Change-Id: I01a2ae528be8f0fa8683c608b3786b5db282d0e1 Signed-off-by: Suyeon Hwang (cherry picked from commit 96dd49ebd12b1c1853071cfe5e570e183c6133ee) --- diff --git a/client/tts_tidl.c b/client/tts_tidl.c index 1cca1e9..7a1f012 100644 --- a/client/tts_tidl.c +++ b/client/tts_tidl.c @@ -32,6 +32,9 @@ typedef struct { } tts_tidl_info_s; static GList* g_tidl_infos = NULL; +static GSList *g_destruction_scheduled_handles = NULL; + +static Ecore_Idler *g_destroy_handles_idler = NULL; static tts_tidl_info_s* __get_tidl_info_s(unsigned int uid) @@ -66,6 +69,11 @@ static void __notify_cb(void *user_data, int pid, int uid, bundle *msg) RETM_IF(NULL == client, "[ERROR] Fail to get client"); unsigned int u_uid = (unsigned int)uid; + if (NULL != g_slist_find(g_destruction_scheduled_handles, user_data)) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] This message is for destroyed handle."); + return; + } + SLOG(LOG_DEBUG, TAG_TTSC, "__notify_cb is invoked pid(%d) uid(%u)", pid, u_uid); bundle_get_str(msg, TTS_BUNDLE_METHOD, &method); @@ -215,14 +223,34 @@ int tts_tidl_open_connection(unsigned int uid) return TTS_ERROR_NONE; } -static inline int __destroy_rpc_port(tts_tidl_info_s* info) +static void destroy_scheduled_handle(gpointer data) +{ + rpc_port_proxy_tts_h rpc_h = (rpc_port_proxy_tts_h)data; + int ret = rpc_port_proxy_tts_destroy(rpc_h); + if (RPC_PORT_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to destroy handle. ret(%d/%s)", ret, get_error_message(ret)); + } +} + +static Eina_Bool destroy_scheduled_handles_by_ecore_idler(void *user_data) { - RETVM_IF(NULL == info->rpc_h, TTS_ERROR_NONE, "[TIDL] Handle is already destroyed"); + SLOG(LOG_INFO, TAG_TTSC, "[INFO] Destroy RPC handles those are scheduled to be destroyed."); + g_slist_free_full(g_destruction_scheduled_handles, destroy_scheduled_handle); + g_destruction_scheduled_handles = NULL; + g_destroy_handles_idler = NULL; - if (RPC_PORT_ERROR_NONE != rpc_port_proxy_tts_destroy(info->rpc_h)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to destroy handle"); - return TTS_ERROR_OPERATION_FAILED; + return EINA_FALSE; +} + +static inline void destroy_rpc_port(tts_tidl_info_s* info) +{ + RETM_IF(NULL == info->rpc_h, "[TIDL] Handle is already destroyed"); + + g_destruction_scheduled_handles = g_slist_append(g_destruction_scheduled_handles, info->rpc_h); + if (NULL == g_destroy_handles_idler) { + g_destroy_handles_idler = ecore_idler_add(destroy_scheduled_handles_by_ecore_idler, NULL); } + info->rpc_h = NULL; info->notify_cb_h = NULL; @@ -232,8 +260,6 @@ static inline int __destroy_rpc_port(tts_tidl_info_s* info) info->register_callback_invoked = false; info->connection_requesting = false; info->connected = false; - - return TTS_ERROR_NONE; } int tts_tidl_close_connection(unsigned int uid) @@ -246,11 +272,15 @@ int tts_tidl_close_connection(unsigned int uid) tts_tidl_info_s* info = __get_tidl_info_s(uid); RETVM_IF(NULL == info, TTS_ERROR_INVALID_PARAMETER, "[ERROR] Fail to get tidl info"); - if (TTS_ERROR_NONE != __destroy_rpc_port(info)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to disconnect"); - return TTS_ERROR_OPERATION_FAILED; + destroy_rpc_port(info); + if (g_destroy_handles_idler) { + ecore_idler_del(g_destroy_handles_idler); + g_destroy_handles_idler = NULL; } + g_slist_free_full(g_destruction_scheduled_handles, destroy_scheduled_handle); + g_destruction_scheduled_handles = NULL; + free(info->engine_app_id); info->engine_app_id = NULL; @@ -297,7 +327,7 @@ static int __create_notify_callback_handle(tts_tidl_info_s* info) return TTS_ERROR_OUT_OF_MEMORY; } - rpc_port_proxy_tts_notify_cb_set_callback(info->notify_cb_h, __notify_cb, NULL); + rpc_port_proxy_tts_notify_cb_set_callback(info->notify_cb_h, __notify_cb, (void *)info->rpc_h); rpc_port_proxy_tts_notify_cb_set_once(info->notify_cb_h, false); return TTS_ERROR_NONE; @@ -367,10 +397,7 @@ static inline int __create_rpc_port(tts_tidl_info_s* info, const char* engine_id static int __reset_rpc_port(tts_tidl_info_s* info, const char* engine_id) { - if (TTS_ERROR_NONE != __destroy_rpc_port(info)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to destroy old rpc port"); - return TTS_ERROR_OPERATION_FAILED; - } + destroy_rpc_port(info); if (TTS_ERROR_NONE != __create_rpc_port(info, engine_id)) { SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to create new rpc port"); @@ -441,7 +468,7 @@ static int __convert_and_handle_tidl_error(int ret, tts_tidl_info_s* info) switch (ret) { case RPC_PORT_ERROR_IO_ERROR: SLOG(LOG_INFO, TAG_TTSC, "[INFO] IO error occurs. Destroy old rpc port"); - __destroy_rpc_port(info); + destroy_rpc_port(info); return TTS_ERROR_IO_ERROR; case RPC_PORT_ERROR_OUT_OF_MEMORY: @@ -572,10 +599,7 @@ int tts_tidl_request_finalize(unsigned int uid) } tts_client_set_start_listening(uid, false); - if (TTS_ERROR_NONE != __destroy_rpc_port(info)) { - SLOG(LOG_ERROR, TAG_TTSC, "[ERROR] Fail to destroy rpc port. ret(%d)", ret); - return TTS_ERROR_OPERATION_FAILED; - } + destroy_rpc_port(info); SLOG(LOG_ERROR, TAG_TTSC, ">>>> Success tts finalize. uid(%u)", uid); return TTS_ERROR_NONE;