Skip to content

Commit 2c9329c

Browse files
committed
Fix crash when pasting history due to memory corruption.
At the same time do some refactoring to make the code clearer. Add some comments in place of a FIXME explaining why we cannot free the params in the job clean-up routine. Fixes #19612.
1 parent 4abaccc commit 2c9329c

File tree

1 file changed

+72
-24
lines changed

1 file changed

+72
-24
lines changed

src/control/jobs/control_jobs.c

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ typedef struct _images_job_data_t
123123
gboolean overwrite;
124124
} _images_job_data_t;
125125

126+
static _images_job_data_t* _dup_images_job_data_t(_images_job_data_t *data)
127+
{
128+
_images_job_data_t*d = g_malloc(sizeof(_images_job_data_t));
129+
memcpy(d, data, sizeof(_images_job_data_t));
130+
d->imgs = g_list_copy(d->imgs);
131+
d->styles = g_list_copy(d->styles);
132+
return d;
133+
}
134+
126135
static inline gboolean _job_cancelled(dt_job_t *job)
127136
{
128137
return dt_control_job_get_state(job) == DT_JOB_STATE_CANCELLED;
@@ -248,9 +257,13 @@ static void _control_image_enumerator_cleanup(void *p)
248257

249258
g_list_free(params->index);
250259
params->index = NULL;
251-
//FIXME: we need to free params->data to avoid a memory leak, but
252-
//doing so here causes memory corruption....
253-
// g_free(params->data);
260+
261+
// we cannot free params->data as this is either a Glist * or an
262+
// allocated struct (_images_job_data_t). It is the responsibility
263+
// of the runner to free the data if needed. Furthermore, note that
264+
// some jobs are passing the images list to a signal which is turns
265+
// will free the list.
266+
params->data = NULL;
254267

255268
if(params->blocking)
256269
g_main_context_invoke(NULL, _cursor_clear_busy, NULL);
@@ -1620,6 +1633,7 @@ static int32_t _control_paste_history_job_run(dt_job_t *job)
16201633
dt_collection_update_query(darktable.collection,
16211634
DT_COLLECTION_CHANGE_RELOAD, DT_COLLECTION_PROP_UNDEF,
16221635
(GList*)paste_data->imgs); // frees list of images
1636+
16231637
g_free(params->data);
16241638
params->data = NULL;
16251639

@@ -2296,11 +2310,11 @@ void dt_control_refresh_exif()
22962310

22972311
static void _add_history_job(GList *imgs,
22982312
const char *title,
2299-
dt_job_execute_callback execute,
2300-
_images_job_data_t *images_job_data)
2313+
dt_job_execute_callback execute)
23012314
{
23022315
if(!imgs || !execute)
23032316
return;
2317+
23042318
GList *link = darktable.develop
23052319
? g_list_find(imgs, GINT_TO_POINTER(darktable.develop->image_storage.id))
23062320
: NULL;
@@ -2311,17 +2325,10 @@ static void _add_history_job(GList *imgs,
23112325
// images to be processed, and run it synchronously by itself
23122326
imgs = g_list_remove_link(imgs, link);
23132327

2314-
if(images_job_data)
2315-
images_job_data->imgs = link;
2316-
23172328
dt_control_add_job(DT_JOB_QUEUE_SYNCHRONOUS,
23182329
_control_generic_images_job_create(execute, title, 0,
2319-
images_job_data
2320-
? (gpointer)images_job_data
2321-
: (gpointer)link,
2330+
(gpointer)link,
23222331
PROGRESS_BLOCKING, FALSE));
2323-
if(images_job_data)
2324-
images_job_data->imgs = imgs;
23252332
}
23262333
// if there are any images left in the list after removing the
23272334
// darkroom image, process them asynchronously but block user
@@ -2330,9 +2337,46 @@ static void _add_history_job(GList *imgs,
23302337
{
23312338
dt_control_add_job(DT_JOB_QUEUE_USER_FG,
23322339
_control_generic_images_job_create(execute, title, 0,
2333-
images_job_data
2334-
? (gpointer)images_job_data
2335-
: (gpointer)imgs,
2340+
(gpointer)imgs,
2341+
PROGRESS_BLOCKING, FALSE));
2342+
}
2343+
}
2344+
2345+
static void _add_history_job_data(const char *title,
2346+
dt_job_execute_callback execute,
2347+
_images_job_data_t *images_job_data)
2348+
{
2349+
if(!images_job_data->imgs || !execute)
2350+
return;
2351+
2352+
GList *link = darktable.develop
2353+
? g_list_find(images_job_data->imgs,
2354+
GINT_TO_POINTER(darktable.develop->image_storage.id))
2355+
: NULL;
2356+
2357+
if(link)
2358+
{
2359+
// remove the image in darkroom center view from the list of
2360+
// images to be processed, and run it synchronously by itself
2361+
_images_job_data_t *d = _dup_images_job_data_t(images_job_data);
2362+
g_list_free(d->imgs);
2363+
d->imgs = link;
2364+
2365+
images_job_data->imgs = g_list_remove_link(images_job_data->imgs, link);
2366+
2367+
dt_control_add_job(DT_JOB_QUEUE_SYNCHRONOUS,
2368+
_control_generic_images_job_create(execute, title, 0,
2369+
(gpointer)d,
2370+
PROGRESS_BLOCKING, FALSE));
2371+
}
2372+
// if there are any images left in the list after removing the
2373+
// darkroom image, process them asynchronously but block user
2374+
// interactions other than cancellation
2375+
if(images_job_data->imgs)
2376+
{
2377+
dt_control_add_job(DT_JOB_QUEUE_USER_FG,
2378+
_control_generic_images_job_create(execute, title, 0,
2379+
(gpointer)images_job_data,
23362380
PROGRESS_BLOCKING, FALSE));
23372381
}
23382382
}
@@ -2353,9 +2397,11 @@ void dt_control_paste_history(GList *imgs)
23532397
images_job_data->duplicate = FALSE;
23542398
images_job_data->overwrite = FALSE;
23552399

2356-
_add_history_job(imgs, N_("paste history"),
2357-
&_control_paste_history_job_run, images_job_data);
2400+
_add_history_job_data(N_("paste history"),
2401+
&_control_paste_history_job_run, images_job_data);
23582402
}
2403+
else
2404+
g_list_free(imgs);
23592405
}
23602406

23612407
void dt_control_paste_parts_history(GList *imgs)
@@ -2381,8 +2427,8 @@ void dt_control_paste_parts_history(GList *imgs)
23812427
images_job_data->duplicate = FALSE;
23822428
images_job_data->overwrite = darktable.view_manager->copy_paste.is_overwrite_set;
23832429

2384-
_add_history_job(imgs, N_("paste history"),
2385-
&_control_paste_history_job_run, images_job_data);
2430+
_add_history_job_data(N_("paste history"),
2431+
&_control_paste_history_job_run, images_job_data);
23862432
}
23872433
}
23882434
else
@@ -2395,9 +2441,10 @@ void dt_control_compress_history(GList *imgs)
23952441
{
23962442
(void)dt_history_compress(GPOINTER_TO_INT(imgs->data));
23972443
g_list_free(imgs);
2398-
return;
23992444
}
2400-
_add_history_job(imgs, N_("compress history"), &_control_compress_history_job_run, NULL);
2445+
else
2446+
_add_history_job(imgs, N_("compress history"),
2447+
&_control_compress_history_job_run);
24012448
}
24022449

24032450
void dt_control_discard_history(GList *imgs)
@@ -2406,9 +2453,10 @@ void dt_control_discard_history(GList *imgs)
24062453
{
24072454
dt_history_delete(GPOINTER_TO_INT(imgs->data), TRUE);
24082455
g_list_free(imgs);
2409-
return;
24102456
}
2411-
_add_history_job(imgs, N_("discard history"), &_control_discard_history_job_run, NULL);
2457+
else
2458+
_add_history_job(imgs, N_("discard history"),
2459+
&_control_discard_history_job_run);
24122460
}
24132461

24142462
void dt_control_apply_styles(GList *imgs, GList *styles, const gboolean duplicate)

0 commit comments

Comments
 (0)