Fix double free issue 60/83560/5 accepted/tizen/mobile/20160815.233404 submit/tizen/20160812.083141
authorAndrii Sokolenko <a.sokolenko@samsung.com>
Thu, 11 Aug 2016 14:28:47 +0000 (17:28 +0300)
committerAndrii Sokolenko <a.sokolenko@samsung.com>
Fri, 12 Aug 2016 08:29:00 +0000 (11:29 +0300)
Change-Id: I67b973be65e4016dd1638b9662c949047e0c499e
Signed-off-by: Andrii Sokolenko <a.sokolenko@samsung.com>
src/tdm_sprd_pp.c

index f03c185..9a7b74e 100644 (file)
@@ -62,6 +62,7 @@ typedef struct _tdm_sprd_pp_data {
        int roadmap_changed;
        int new_buffers;
        int first_event;
+       int pp_need_destroy;
        struct list_head link;
 } tdm_sprd_pp_data;
 
@@ -583,7 +584,6 @@ _tdm_sprd_pp_worker (tdm_sprd_pp_data *pp_data)
        return TDM_ERROR_NONE;
 }
 
-
 void
 tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
 {
@@ -594,6 +594,7 @@ tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
                TDM_ERR("invalid params");
                return;
        }
+
        RETURN_VOID_IF_FAIL(_tdm_sprd_pp_check_struct(pp_data));
        TDM_DBG("pp %p(%d) index(%d, %d) prop_id(%u)", pp_data, pp_data->stamp, hw_ipp_p->buf_id[0],
                        hw_ipp_p->buf_id[1], hw_ipp_p->prop_id);
@@ -601,6 +602,14 @@ tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
                TDM_DBG("pp %p(%d) got a first event. ", pp_data, pp_data->stamp);
                pp_data->first_event = 1;
        }
+
+       if (pp_data->pp_need_destroy) {
+               TDM_DBG("pp %p(%d) Deferred event of delete", pp_data, pp_data->stamp);
+               LIST_DEL(&pp_data->link);
+               free(pp_data);
+               return;
+       }
+
        if ((done_task = pp_data->current_task_p) == NULL) {
                TDM_ERR("pp %p(%d) received wrong event", pp_data, pp_data->stamp);
                return;
@@ -614,6 +623,7 @@ tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
        done_task->status = TASK_DONE;
        TDM_DBG("pp %p(%d). Task %p(%d) done step %d of %d", pp_data, pp_data->stamp, done_task, done_task->stamp,
                        done_task->current_step+1, done_task->max_step);
+
        if (_tdm_sprd_pp_cmd(pp_data,
                                                 done_task->prop_id[done_task->current_step],
                                                 IPP_PAUSE) != TDM_ERROR_NONE) {
@@ -621,6 +631,7 @@ tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
                                pp_data->stamp, done_task->prop_id[done_task->current_step]);
                return;
        }
+
        if (_tdm_sprd_pp_worker(pp_data) != TDM_ERROR_NONE) {
                TDM_ERR("pp %p(%d) worker return ERROR", pp_data,
                                pp_data->stamp);
@@ -674,10 +685,20 @@ tdm_sprd_pp_create(tdm_sprd_data *sprd_data, tdm_error *error)
 
        pp_data->sprd_data = sprd_data;
        pp_data->stamp = pp_stamp++;
+       pp_data->pp_need_destroy = 0;
        if (!pp_list_init) {
                pp_list_init = 1;
                LIST_INITHEAD(&pp_list);
        }
+       /* Find old pp_data and remove*/
+       tdm_sprd_pp_data *pp_data_cur = NULL, *pp_data_next = NULL;
+       LIST_FOR_EACH_ENTRY_SAFE(pp_data_cur, pp_data_next, &pp_list, link) {
+               if (pp_data_cur->pp_need_destroy) {
+                       LIST_DEL(&pp_data_cur->link);
+                       free(pp_data_cur);
+               }
+       }
+
        LIST_INITHEAD(&pp_data->pending_buffer_list);
        LIST_INITHEAD(&pp_data->pending_tasks_list);
        LIST_INITHEAD(&pp_data->prop_id_list);
@@ -695,25 +716,34 @@ sprd_pp_destroy(tdm_pp *pp)
        tdm_sprd_prop_id *prop_id = NULL, *next_prop_id = NULL;
        RETURN_VOID_IF_FAIL(_tdm_sprd_pp_check_struct(pp_data));
        TDM_DBG("pp %p(%d). Destroy", pp_data, pp_data->stamp);
+
+       LIST_FOR_EACH_ENTRY_SAFE (prop_id, next_prop_id, &pp_data->prop_id_list, link) {
+               _tdm_sprd_pp_cmd(pp_data, prop_id->prop_id, IPP_STOP);
+       }
+
        LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
                LIST_DEL(&b->link);
                free(b);
        }
-       if (pp_data->current_task_p && pp_data->current_task_p->status == TASK_CONVERTING) {
-               _tdm_sprd_pp_queue(pp_data, pp_data->current_task_p->prop_id[pp_data->current_task_p->current_step],
-                                                  pp_data->current_task_p->buffers[pp_data->current_task_p->current_step].src,
-                                                  pp_data->current_task_p->buffers[pp_data->current_task_p->current_step].dst, IPP_BUF_DEQUEUE);
-               _tdm_sprd_pp_destroy_task(pp_data, pp_data->current_task_p);
-       }
+
        LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_data->pending_tasks_list, link) {
                LIST_DEL(&task->link);
                _tdm_sprd_pp_destroy_task(pp_data, task);
        }
-       LIST_FOR_EACH_ENTRY_SAFE (prop_id, next_prop_id, &pp_data->prop_id_list, link) {
-               _tdm_sprd_pp_cmd(pp_data, prop_id->prop_id, IPP_STOP);
+
+       if (pp_data->current_task_p && pp_data->current_task_p->status == TASK_CONVERTING) {
+               TDM_DBG("pp %p(%d) Still converting. Should Remove after callback", pp_data, pp_data->stamp);
+               pp_data->pp_need_destroy = 1;
+               _tdm_sprd_pp_destroy_task(pp_data, pp_data->current_task_p);
+               pp_data->current_task_p = NULL;
        }
+
+       if (pp_data->pp_need_destroy)
+               return;
+
        LIST_DEL(&pp_data->link);
        free(pp_data);
+
 }
 
 static tdm_error
@@ -832,6 +862,10 @@ sprd_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
        RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
        RETURN_VAL_IF_FAIL(_tdm_sprd_pp_check_struct(pp_data), TDM_ERROR_INVALID_PARAMETER);
        TDM_DBG("pp %p(%d). Set new info.", pp_data, pp_data->stamp);
+       if (pp_data->pp_need_destroy) {
+               TDM_WRN("pp %p(%d) Will remove. Ignoring request.", pp_data, pp_data->stamp);
+               return TDM_ERROR_BAD_REQUEST;
+       }
        if (info->sync) {
                TDM_ERR("pp %p(%d). not support sync mode currently", pp_data, pp_data->stamp);
                return TDM_ERROR_INVALID_PARAMETER;
@@ -852,6 +886,10 @@ sprd_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
        RETURN_VAL_IF_FAIL(src, TDM_ERROR_INVALID_PARAMETER);
        RETURN_VAL_IF_FAIL(dst, TDM_ERROR_INVALID_PARAMETER);
        RETURN_VAL_IF_FAIL(_tdm_sprd_pp_check_struct(pp_data), TDM_ERROR_INVALID_PARAMETER);
+       if (pp_data->pp_need_destroy) {
+               TDM_WRN("pp %p(%d) Will remove. Ignoring request.", pp_data, pp_data->stamp);
+               return TDM_ERROR_BAD_REQUEST;
+       }
        buffer = calloc(1, sizeof(tdm_sprd_pp_buffer));
        if (!buffer) {
                TDM_ERR("pp %p(%d). Alloc failed", pp_data, pp_data->stamp);
@@ -874,6 +912,10 @@ sprd_pp_commit(tdm_pp *pp)
 {
        tdm_sprd_pp_data *pp_data = (tdm_sprd_pp_data *) pp;
        RETURN_VAL_IF_FAIL(_tdm_sprd_pp_check_struct(pp_data), TDM_ERROR_INVALID_PARAMETER);
+       if (pp_data->pp_need_destroy) {
+               TDM_WRN("pp %p(%d) Will remove. Ignoring request.", pp_data, pp_data->stamp);
+               return TDM_ERROR_BAD_REQUEST;
+       }
        if (pp_data->roadmap_changed) {
                unsigned int i, need_postpond = 0;
                for (i = 0; i < pp_data->roadmap.max_step; i++) {