java-topology/defects/libopenshot-0001/patch/libopenshot-0001.patch

73 lines
3.3 KiB
Diff

# UNDF: UNDF-2026-000001118
# UNDF: (leave blank)
# CWE-407: Algorithmic Complexity (list membership inside per-frame loop)
# libopenshot ObjectDetection effect: display_classes filter uses std::find on a
# std::vector<std::string> inside the per-detection loop that runs every rendered frame.
#
# Defective path (src/effects/ObjectDetection.cpp, two sites):
#
# Site 1 (line 76-79, GetFrame hot path):
# for (int i = 0; i < detections.boxes.size(); i++) {
# if (!display_classes.empty() &&
# std::find(display_classes.begin(), display_classes.end(),
# classNames[detections.classIds.at(i)]) == display_classes.end())
# continue;
# }
#
# Site 2 (line 269-284, GetPropertiesJSON):
# for (int i = 0; i < detections.boxes.size(); i++) {
# auto it = std::find(display_classes.begin(), display_classes.end(), className);
# }
#
# Complexity: O(D * C) per frame, where D = detections per frame, C = |display_classes|.
# With D=50 detections and C=20 filter classes this is 1000 string comparisons per frame.
# At 30 fps over a 1-minute video: 1,800,000 comparisons vs 90,000 with a hash set (20x).
#
# Fix: replace display_classes std::vector<std::string> with
# std::unordered_set<std::string>. Membership test drops from O(C) to O(1).
# SetJsonValue still populates the set with the same string values.
#
# Severity: MEDIUM. Hot path (every rendered frame), constant-factor overhead per
# detection scales with both frame rate and filter list length.
--- a/src/effects/ObjectDetection.h
+++ b/src/effects/ObjectDetection.h
@@ -72,7 +72,7 @@ namespace openshot {
float confidence_threshold;
bool display_box;
bool display_label;
- std::vector<std::string> display_classes;
+ std::unordered_set<std::string> display_classes;
/// @brief Default constructor
ObjectDetection(std::string clipObDetectDataPath="");
@@ -1,6 +1,7 @@
#include <string>
+#include <unordered_set>
--- a/src/effects/ObjectDetection.cpp
+++ b/src/effects/ObjectDetection.cpp
@@ -76,7 +76,7 @@ std::shared_ptr<Frame> ObjectDetection::GetFrame(std::shared_ptr<Frame> frame,
for (int i = 0; i < detections.boxes.size(); i++) {
if (detections.confidences.at(i) < confidence_threshold ||
(!display_classes.empty() &&
- std::find(display_classes.begin(), display_classes.end(), classNames[detections.classIds.at(i)]) == display_classes.end())) {
+ display_classes.find(classNames[detections.classIds.at(i)]) == display_classes.end())) {
continue;
}
@@ -279,7 +279,7 @@ std::string ObjectDetection::GetPropertiesJSON(int64_t requested_frame) const {
if (!display_classes.empty()) {
- auto it = std::find(display_classes.begin(), display_classes.end(), className);
- if (it == display_classes.end()) {
+ if (display_classes.find(className) == display_classes.end()) {
continue;
}
@@ -388,7 +388,6 @@ void ObjectDetection::SetJsonValue(const Json::Value root) {
display_classes.clear();
if (!root["display_classes"].isNull()) {
for (const auto &s : root["display_classes"]) {
- display_classes.push_back(s.toStyledString());
+ display_classes.insert(s.toStyledString());
}
}