62 lines
2.3 KiB
Diff
62 lines
2.3 KiB
Diff
# UNDF: UNDF-2026-000001147
|
|
# Defect: rawtherapee-0001
|
|
# Component: rtgui/batchqueue.cc — BatchQueue::cancelItems(), headItems(), tailItems()
|
|
# Pattern: CWE-407 — std::find(fd.begin(), fd.end(), entry) inside loop over items
|
|
# Severity: MEDIUM — O(I*Q) where I=items to cancel/move, Q=total queue size
|
|
# Fix: Build unordered_set<> from fd for O(1) lookup in cancelItems; for headItems/tailItems
|
|
# the erase+reinsert is O(Q) per item by nature, but skip items not in fd quickly
|
|
--- a/rtgui/batchqueue.cc
|
|
+++ b/rtgui/batchqueue.cc
|
|
@@ -484,24 +484,22 @@
|
|
void BatchQueue::cancelItems (const std::vector<ThumbBrowserEntryBase*>& items)
|
|
{
|
|
std::set<BatchQueueEntry*> removable_bqes;
|
|
|
|
{
|
|
MYWRITERLOCK(l, entryRW);
|
|
|
|
- for (const auto item : items) {
|
|
-
|
|
- const auto entry = static_cast<BatchQueueEntry*> (item);
|
|
-
|
|
- if (entry->processing)
|
|
- continue;
|
|
-
|
|
- const auto pos = std::find (fd.begin (), fd.end (), entry);
|
|
-
|
|
- if (pos == fd.end ())
|
|
- continue;
|
|
-
|
|
- fd.erase (pos);
|
|
-
|
|
- rtengine::ProcessingJob::destroy (entry->job);
|
|
-
|
|
- if (entry->thumbnail)
|
|
- entry->thumbnail->imageRemovedFromQueue ();
|
|
-
|
|
- removable_bqes.insert(entry);
|
|
- }
|
|
+ // Build a set of items to cancel for O(1) lookup during fd iteration
|
|
+ std::unordered_set<ThumbBrowserEntryBase*> to_cancel;
|
|
+ for (const auto item : items) {
|
|
+ const auto entry = static_cast<BatchQueueEntry*> (item);
|
|
+ if (!entry->processing)
|
|
+ to_cancel.insert(entry);
|
|
+ }
|
|
+
|
|
+ // Single-pass removal: iterate fd once, remove matched entries
|
|
+ auto new_end = std::remove_if(fd.begin(), fd.end(), [&](ThumbBrowserEntryBase* e) {
|
|
+ if (to_cancel.count(e)) {
|
|
+ auto* entry = static_cast<BatchQueueEntry*>(e);
|
|
+ rtengine::ProcessingJob::destroy(entry->job);
|
|
+ if (entry->thumbnail)
|
|
+ entry->thumbnail->imageRemovedFromQueue();
|
|
+ removable_bqes.insert(entry);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ });
|
|
+ fd.erase(new_end, fd.end());
|
|
|
|
for (const auto entry : fd)
|
|
entry->selected = false;
|