Add defensive code to avoid crash 29/319929/4 accepted/tizen/unified/20241112.160415
authorJeongmo Yang <jm80.yang@samsung.com>
Tue, 5 Nov 2024 08:39:10 +0000 (17:39 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Mon, 11 Nov 2024 03:30:28 +0000 (12:30 +0900)
- The user callback can be called in __camera_idle_event_callback()
  although handle is destroyed after g_cam_idle_event_lock is unlocked.
- Add new flag to avoid that situation.

[Version] 1.2.1
[Issue Type] Improvement

Change-Id: I965f07768a18cdd82e460b10b3db6cedf626d3f4
Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
include/camera_private.h
packaging/capi-media-camera.spec
src/camera.c

index bd26435b8c7f0103b4b5001a0faa87cb0570e23d..bc082ea303b6a7ce80304feb34bbc544166829ff 100644 (file)
@@ -187,6 +187,7 @@ typedef struct _camera_cb_info_s {
        gpointer user_data[MUSE_CAMERA_EVENT_TYPE_NUM];
        GMutex user_cb_lock[MUSE_CAMERA_EVENT_TYPE_NUM];
        gboolean invoke_preview_cb;
+       gboolean is_in_idle_cb;
 
        /* tbm */
        tbm_bufmgr bufmgr;
index ee0fb19711985026131f0b02140350da60c9b837..40e8899feb425773ec88727eb13179c2ca5a8b58 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-camera
 Summary:    A Camera API
-Version:    1.2.0
+Version:    1.2.1
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 387b50a2549a9b4f6fb015a6ebe837dce3d4d7db..07d4d5fec60ebebc161c18c0205202d2cb0d3346 100644 (file)
@@ -1752,7 +1752,6 @@ static gboolean __camera_idle_event_callback(gpointer data)
        cb_info = cam_idle_event->cb_info;
        if (cb_info == NULL) {
                CAM_LOG_WARNING("NULL cb_info for event[%d] %p", cam_idle_event->event, cam_idle_event);
-               g_mutex_unlock(&g_cam_idle_event_lock);
                goto IDLE_EVENT_CALLBACK_DONE;
        }
 
@@ -1760,12 +1759,20 @@ static gboolean __camera_idle_event_callback(gpointer data)
        if (cb_info->idle_event_list)
                cb_info->idle_event_list = g_list_remove(cb_info->idle_event_list, (gpointer)cam_idle_event);
 
+       cb_info->is_in_idle_cb = TRUE;
+
        g_mutex_unlock(&g_cam_idle_event_lock);
 
        /* user callback */
        __camera_client_user_callback(cb_info, cam_idle_event->recv_msg, cam_idle_event->event, cam_idle_event->tfd);
 
+       g_mutex_lock(&g_cam_idle_event_lock);
+
+       cb_info->is_in_idle_cb = FALSE;
+
 IDLE_EVENT_CALLBACK_DONE:
+       g_mutex_unlock(&g_cam_idle_event_lock);
+
        /* release event */
        g_free(cam_idle_event);
 
@@ -1920,7 +1927,6 @@ static void __camera_deactivate_idle_event_all(camera_cb_info_s *cb_info)
 {
        camera_idle_event_s *cam_idle_event = NULL;
        GList *list = NULL;
-       g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&g_cam_idle_event_lock);
 
        if (cb_info == NULL) {
                CAM_LOG_ERROR("cb_info is NULL");
@@ -1939,7 +1945,7 @@ static void __camera_deactivate_idle_event_all(camera_cb_info_s *cb_info)
                list = g_list_next(list);
 
                if (!cam_idle_event) {
-                       CAM_LOG_WARNING("Fail to remove idle event. The event is NULL");
+                       CAM_LOG_WARNING("The event is NULL");
                        continue;
                }
 
@@ -2871,26 +2877,36 @@ int camera_destroy(camera_h camera)
        int ret = CAMERA_ERROR_NONE;
        muse_camera_api_e api = MUSE_CAMERA_API_DESTROY;
        camera_cli_s *pc = (camera_cli_s *)camera;
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&g_cam_idle_event_lock);
 
        CAMERA_CHECK_HANDLE_RETURN_VAL(pc, CAMERA_ERROR_INVALID_PARAMETER);
 
        CAM_LOG_INFO("Enter");
 
+       if (pc->cb_info->is_in_idle_cb) {
+               CAM_LOG_ERROR("should not be called in idle callback");
+               return CAMERA_ERROR_INVALID_OPERATION;
+       }
+
        if (pc->cb_info->is_server_connected)
                _camera_msg_send(api, NULL, pc->cb_info, &ret, CAMERA_CB_TIMEOUT);
        else
                CAM_LOG_WARNING("server disconnected. release resource without send message.");
 
-       if (ret == CAMERA_ERROR_NONE) {
-               __camera_deactivate_idle_event_all(pc->cb_info);
-               __camera_client_callback_destroy(pc->cb_info);
-               pc->cb_info = NULL;
-
-               g_free(pc);
-               pc = NULL;
+       if (ret != CAMERA_ERROR_NONE) {
+               CAM_LOG_ERROR("handle destroy failed[0x%x]", ret);
+               return ret;
        }
 
-       CAM_LOG_INFO("ret : 0x%x", ret);
+       __camera_deactivate_idle_event_all(pc->cb_info);
+
+       g_clear_pointer(&locker, g_mutex_locker_free);
+
+       __camera_client_callback_destroy(pc->cb_info);
+
+       g_free(pc);
+
+       CAM_LOG_INFO("done");
 
        return ret;
 }