From 3dfd9d84ebc8047d466ec7ff5ea2440fa044a903 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 25 Jul 2024 17:40:01 +0200 Subject: [PATCH] Fix memory leak when using grease pencil clone brush Caused by parallel access to static clipboard storage: Multiple threads could end up calling `ensure_grease_pencil_clipboard()` in parallel. Here this resulted in a surprisingly reliable memory leak. Use a simple mutex lock to prevent unsynchronized access. Steps to reproduce were: - Add Grease Pencil object - Enter grease pencil Sculpt mode - Select Clone brush asset - Click in 3D Viewport - Quit Blender (see console log for leak reports) Pull Request: https://projects.blender.org/blender/blender/pulls/125428 --- .../editors/grease_pencil/intern/grease_pencil_edit.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc index 9273d629a7d..5da68eadbd1 100644 --- a/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc @@ -2220,8 +2220,13 @@ static struct Clipboard { int materials_in_source_num; } *grease_pencil_clipboard = nullptr; +/** The clone brush accesses the clipboard from multiple threads. Protect from parallel access. */ +std::mutex grease_pencil_clipboard_lock; + static Clipboard &ensure_grease_pencil_clipboard() { + std::scoped_lock lock(grease_pencil_clipboard_lock); + if (grease_pencil_clipboard == nullptr) { grease_pencil_clipboard = MEM_new(__func__); } @@ -2371,6 +2376,7 @@ static bool grease_pencil_paste_strokes_poll(bContext *C) return false; } + std::scoped_lock lock(grease_pencil_clipboard_lock); /* Check for curves in the Grease Pencil clipboard. */ return (grease_pencil_clipboard && grease_pencil_clipboard->curves.curves_num() > 0); } @@ -2412,6 +2418,8 @@ static void GREASE_PENCIL_OT_copy(wmOperatorType *ot) void clipboard_free() { + std::scoped_lock lock(grease_pencil_clipboard_lock); + if (grease_pencil_clipboard) { MEM_delete(grease_pencil_clipboard); grease_pencil_clipboard = nullptr;