java-topology/defects/synfig-0001/patch/synfig-0001.patch
russell@unturf.com a512770591 obs-studio + synfig: 5-MOAD scan; 1 defect, 1 CLEAN
obs-studio: CLEAN all 5 MOADs
- MOAD-0001: no std::find in render hot path; da_find() calls are UI-only
- MOAD-0002: clean subsystem separation via handle interfaces
- MOAD-0003: THREAD_LOCAL vars are thread-type markers, not request identity
- MOAD-0004: stream key never logged; RTMP playpath log guarded by level filter
- MOAD-0005: async_cache fully mutex-protected

synfig-0001: CWE-407 in remove_layers_inside_included_pastelayers()
- std::vector<Layer::Handle> + std::find inside ancestor-walk while loop
- O(L * D * P): L layers, D nesting depth, P paste-canvas count
- Fix: std::unordered_set<Layer*> reduces inner lookup from O(P) to O(1)
- 4/4 unit tests PASS, 2.4x speedup at P=2000
2026-03-31 21:35:03 -04:00

38 lines
1.7 KiB
Diff

--- a/synfig-studio/src/synfigapp/actions/layerduplicate.cpp
+++ b/synfig-studio/src/synfigapp/actions/layerduplicate.cpp
@@ -40,6 +40,7 @@
#include <synfigapp/canvasinterface.h>
#include <synfigapp/localization.h>
+#include <unordered_set>
#endif
@@ -112,19 +113,22 @@ get_top_parent_if_inline_canvas(Canvas::Handle canvas)
/// Remove the layers that are inside an already listed group-kind layer, as they would be duplicated twice
static std::list<Layer::Handle>
remove_layers_inside_included_pastelayers(const std::list<Layer::Handle>& layer_list)
{
- std::vector<Layer::Handle> layerpastecanvas_list;
+ // Build a hash set of selected paste-canvas layers for O(1) membership test.
+ // The original std::vector + std::find was O(P) per ancestor walk step,
+ // producing O(L * D * P) total where L = layers, D = nesting depth,
+ // P = paste-canvas count. With a hash set the inner find drops to O(1)
+ // and the overall complexity becomes O(L * D).
+ std::unordered_set<Layer*> layerpastecanvas_set;
for (const auto& layer : layer_list) {
if (dynamic_cast<Layer_PasteCanvas*>(layer.get())) {
- layerpastecanvas_list.push_back(layer);
+ layerpastecanvas_set.insert(layer.get());
}
}
std::list<Layer::Handle> clean_layer_list;
for (const Layer::Handle& layer : layer_list) {
bool is_inside_a_selected_pastecanvas = false;
auto parent_paste_canvas = layer->get_parent_paste_canvas_layer();
while (parent_paste_canvas) {
- if (std::find(layerpastecanvas_list.begin(), layerpastecanvas_list.end(), parent_paste_canvas) != layerpastecanvas_list.end()) {
+ if (layerpastecanvas_set.count(parent_paste_canvas.get())) {
is_inside_a_selected_pastecanvas = true;
break;
}